﻿
using Xacml.Core.Interfaces;
using Xacml.Core.Runtime;
using System.Xml;

namespace Xacml.Core.Runtime.Functions
{
  public class XPathNodeMatch : FunctionBase
  {
    public override string Id
    {
      get
      {
        return "urn:oasis:names:tc:xacml:1.0:function:anyURI-equal";
      }
    }

    public override IDataType Returns
    {
      get
      {
        return (IDataType) DataTypeDescriptor.Boolean;
      }
    }

    public override IDataType[] Arguments
    {
      get
      {
        return new IDataType[2]
        {
          (IDataType) DataTypeDescriptor.String,
          (IDataType) DataTypeDescriptor.String
        };
      }
    }

    public override EvaluationValue Evaluate(EvaluationContext context, params IFunctionParameter[] args)
    {
      XmlDocument xmlDocument = context.ContextDocument.XmlDocument;
      if (context.ContextDocument.XmlNamespaceManager == null)
        context.ContextDocument.AddNamespaces(context.PolicyDocument.Namespaces);
      string stringArgument1 = this.GetStringArgument(args, 0);
      XmlNodeList xmlNodeList1 = xmlDocument.DocumentElement.SelectNodes(stringArgument1, context.ContextDocument.XmlNamespaceManager);
      string stringArgument2 = this.GetStringArgument(args, 1);
      XmlNodeList xmlNodeList2 = xmlDocument.DocumentElement.SelectNodes(stringArgument2, context.ContextDocument.XmlNamespaceManager);
      foreach (XmlNode firstNode in xmlNodeList1)
      {
        foreach (XmlNode secondNode in xmlNodeList2)
        {
          if (firstNode == secondNode)
            return EvaluationValue.True;
          if (firstNode.Attributes != null && secondNode.Attributes != null)
          {
            foreach (XmlNode xmlNode1 in (XmlNamedNodeMap) firstNode.Attributes)
            {
              foreach (XmlNode xmlNode2 in (XmlNamedNodeMap) secondNode.Attributes)
              {
                if (xmlNode1 == xmlNode2)
                  return EvaluationValue.True;
              }
            }
          }
          if (this.CompareChildNodes(firstNode, secondNode))
            return EvaluationValue.True;
        }
      }
      return EvaluationValue.False;
    }

    private bool CompareChildNodes(XmlNode firstNode, XmlNode secondNode)
    {
      if (firstNode.ChildNodes != null)
      {
        foreach (XmlNode firstNode1 in firstNode.ChildNodes)
        {
          if (firstNode1 == secondNode || this.CompareChildNodes(firstNode1, secondNode))
            return true;
        }
      }
      return false;
    }
  }
}
